 package com.example.photongrid;
  

import com.jme3.app.SimpleApplication;
import com.jme3.font.BitmapText;
import com.jme3.input.ChaseCamera;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.JoyAxisTrigger;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.TouchListener;
import com.jme3.input.controls.TouchTrigger;
import com.jme3.input.event.TouchEvent;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.CameraControl.ControlDirection;
import com.jme3.scene.shape.Box;
import com.jme3.system.AppSettings;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.texture.Texture;

import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
 
/** Sample 5 - how to map keys and mousebuttons to actions */
public class StateManagerServer extends SimpleApplication implements TouchListener{
  
  // global variables to be used by both init and simpleUpdate
   /** Pick a Target Using the Mouse Pointer. <ol><li>Map "pick target" action to a MouseButtonTrigger. <li>flyCam.setEnabled(false); <li>inputManager.setCursorVisible(true); <li>Implement action in AnalogListener (TODO).</ol>
 */
  
  TerrainQuad terrain;
  Boolean isRunning=true;
  QuadTree objectsOnBoard = null;
  public static Board board;
  int count = 0;
  Node playerNode = new Node("playerNode"); // we need nodes to attach the vehicles to and to attach the 3rd person camera to
  Node player2Node = new Node("player2Node");
  protected Spatial player, player2;
  int angle=0;
  CameraNode camNode;
  ChaseCamera chaseCam;
  public static int c = 0;
  public static final int wallSpacing = 25;
  
  GameStateServer hello = null;
  
  VehicleList vInfo;
  WallList wInfo;
  
  public static ArrayList<VehicleList> vList = new ArrayList<VehicleList>();
  public static ArrayList<WallList> wList = new ArrayList<WallList>();
  public static int updateFlag = 0;
  
  
	  @Override
	  public void simpleInitApp() {
	    //this.start(JmeContext.Type.Headless);
		  
		
		  
		  hello = new GameStateServer();
	    hello.setEnabled(false);
	    stateManager.attach(hello);
	    hello.setEnabled(true);  
	   
	  }
  
  
  
	/* This is the update loop */
	@Override
	public void simpleUpdate(float tpf) {
	         
	}
    
    
    
    
    public void startGame()
    {
        hello.setEnabled(true);
    }
    
    
    
    
    public void updateGame()  // this is the main update loop for the game
    {
    	Boolean updateWalls;
    	
    	if(c == wallSpacing)
    	{
    		updateWalls = true;
    	}
    	else
    	{
    		updateWalls = false;
    	}
    	
        try {
        	
            board.updateBoard(updateWalls);
        } catch (InterruptedException ex) {
            Logger.getLogger(StateManager.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        
        if(Board.vehicleList.get(0).isAlive())
        {
            //player0 position
 
            //Position pos = objectsOnBoard.findNode(Board.vehicleList.get(0).getPosition(), objectsOnBoard.getRoot()).getPosition();
            Position pos = Board.vehicleList.get(0).getPosition();
            //player0's most recent wall position (new wall)
            //Position posWall = objectsOnBoard.findNode(Board.vehicleList.get(0).getPrevPosition(), objectsOnBoard.getRoot()).getPosition();
            Position posWall = Board.vehicleList.get(0).getPrevPosition();
            player.setLocalTranslation(pos.x, 0, pos.y); // move the player's vehicle to the new position from the quad tree

            // make a new wall and place it in the proper position
            if(c == wallSpacing){
                Box b = new Box(Vector3f.ZERO, 15, 30, 30);
                Geometry wall = new Geometry("wall", b);
                Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
                mat.setColor("Color", ColorRGBA.Blue);
                wall.setMaterial(mat);
                wall.setLocalTranslation(posWall.x, 0, posWall.y);
                wall.setLocalRotation(player.getLocalRotation());
                rootNode.attachChild(wall);
                
            //  we will now update the objects which will hold the vehicles and walls that need to be past to the client from the server
                wInfo = new WallList(wall.getLocalTranslation(), wall.getLocalRotation(), 0);
                
            }
            vInfo = new VehicleList(player.getLocalTranslation(), player.getLocalRotation());
            
            vList.add(vInfo);
            wList.add(wInfo);
            updateFlag = 1;
            
            
        }
        else
        {
             
            //destroy vehicle in graphical form
            rootNode.detachChild(player);
            chaseCam.setEnabled(false);
            rootNode.attachChild(camNode);
            //we will then move the camera to view the entire grid that the player's are playing on
            //Move camNode, e.g. behind and above the target:
            camNode.setLocalTranslation(new Vector3f(2500, 6000, 2500));
            //Rotate the camNode to look at the target:
            camNode.lookAt(new Vector3f(2500, 0, 2500), Vector3f.UNIT_Y);
            
        }
       
        
        if(Board.vehicleList.get(1).isAlive())
        {
            //player1 position
            //Position pos2 = objectsOnBoard.findNode(Board.vehicleList.get(1).getPosition(), objectsOnBoard.getRoot()).getPosition();
            Position pos2 = Board.vehicleList.get(1).getPosition();
            //player1's most recent wall position (new wall)
            //Position posWall2 = objectsOnBoard.findNode(Board.vehicleList.get(1).getPrevPosition(), objectsOnBoard.getRoot()).getPosition();
            Position posWall2 = Board.vehicleList.get(1).getPrevPosition();
            player2.setLocalTranslation(pos2.x, 0, pos2.y);
            
            
             // make a new wall and place it in the proper position
            if(c == wallSpacing){
                Box b2 = new Box(Vector3f.ZERO, 15, 30, 30);
                Geometry wall2 = new Geometry("wall", b2);
                Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
                mat2.setColor("Color", ColorRGBA.Green);
                wall2.setMaterial(mat2);
                wall2.move(posWall2.x, 0, posWall2.y);
                wall2.setLocalTranslation(posWall2.x, 0, posWall2.y);
                wall2.setLocalRotation(player2.getLocalRotation());
                rootNode.attachChild(wall2);
            //  we will now update the objects which will hold the vehicles and walls that need to be past to the client from the server
                wInfo = new WallList(wall2.getLocalTranslation(), wall2.getLocalRotation(), 0);
                
            }
            vInfo = new VehicleList(player.getLocalTranslation(), player.getLocalRotation());
            
            vList.add(vInfo);
            wList.add(wInfo);
            updateFlag = 1;
            
        }
        else
        {
            rootNode.detachChild(player2);
                    /** Write text on the screen (HUD) */
          /*  guiNode.detachAllChildren();
            guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
            BitmapText helloText = new BitmapText(guiFont, false);
            helloText.setSize(guiFont.getCharSet().getRenderedSize());
            helloText.setText("Player 1 Wins!!");
            helloText.setLocalTranslation(300, helloText.getLineHeight(), 500);
            guiNode.attachChild(helloText);*/
 
        }
        count++;
        /*double dchange = Math.random()*20-10;
            if(Board.vehicleList.get(1).getPosition().x>4000 && Math.cos(Board.vehicleList.get(1).getDirection()+dchange)>0 || Board.vehicleList.get(1).getPosition().y>4000 && Math.sin(Board.vehicleList.get(1).getDirection()+ dchange)>0 || Board.vehicleList.get(1).getPosition().x<1000 && Math.cos(Board.vehicleList.get(1).getDirection()+dchange)<0 || Board.vehicleList.get(1).getPosition().y<1000 && Math.sin(Board.vehicleList.get(1).getDirection()+ dchange)<0){
                Board.vehicleList.get(1).changeDirection(Board.vehicleList.get(1).getDirection()-(int)-dchange);
                player2.rotate(0, FastMath.DEG_TO_RAD*(int)-dchange, 0);    
            }
            else{
            Board.vehicleList.get(1).changeDirection(Board.vehicleList.get(1).getDirection()-(int)dchange);
            player2.rotate(0, FastMath.DEG_TO_RAD*(int)dchange, 0);
            }*/
        if(c==wallSpacing){
            
            c = 0;
        }
        else
            c++;
        if(Board.vehicleList.get(0).isBoost() && System.currentTimeMillis() >= Board.vehicleList.get(0).last+5000)
            Board.vehicleList.get(0).stopBoost();
        if(board.gameover())
        {
            //we need gameover effects        
            /** Write text on the screen (HUD) */
            guiNode.detachAllChildren();
            guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
            BitmapText helloText = new BitmapText(guiFont, false);
            helloText.setSize(guiFont.getCharSet().getRenderedSize());
            helloText.setText("GAME OVER");
            helloText.setLocalTranslation(300, helloText.getLineHeight(), 0);
            guiNode.attachChild(helloText);
            //this.stop();
        }
    }
    
    
    public void initializeGame()
  {
      float[] hieght = new float[513];
    Material mat_terrain;
    mat_terrain = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    Texture tex = assetManager.loadTexture("Scenes/grid.jpg");
    mat_terrain.setTexture("ColorMap", tex);
    terrain = new TerrainQuad("my terrain", 65, 65, hieght);
    terrain.setMaterial(mat_terrain);
    terrain.setLocalTranslation(2500f,0f,2500f);
    terrain.setLocalScale(76.92f,0f,76.92f);
    rootNode.attachChild(terrain);
    board = new Board();
    
    board.preparegame();
    
    objectsOnBoard = board.getQuadTree();
    
    //get the position of the node that each vehicle is at
    //Position pos = objectsOnBoard.findNode(Board.vehicleList.get(0).getPosition(), objectsOnBoard.getRoot()).getPosition();
    Position pos = Board.vehicleList.get(0).getPosition();
    //Position pos2 = objectsOnBoard.findNode(Board.vehicleList.get(1).getPosition(), objectsOnBoard.getRoot()).getPosition();
    Position pos2 = Board.vehicleList.get(1).getPosition();
    // make the box for each vehicle and move it to the necessary position
   
 
   Box b = new Box(Vector3f.ZERO, 30, 10, 10);
   player = assetManager.loadModel("Models/lightcycle/lightcycle.j3o");
   player.setLocalScale(30); 
   player.rotate(0,1.55f,0);
    //player = new Geometry("Player", b);
    //Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    //mat.setColor("Color", ColorRGBA.Blue);
    //player.setMaterial(mat);
   player.move(pos.x, 0, pos.y);
    
   Box b2 = new Box(Vector3f.ZERO, 30, 10, 10);
   player2 = assetManager.loadModel("Models/lightcycle/lightcycle.j3o");
   player2.setLocalScale(30); 
   player2.rotate(0,-1.5f,0);
    //player2 = new Geometry("Player", b2);
    //Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    //mat2.setColor("Color", ColorRGBA.Green);
    //player2.setMaterial(mat2);
    player2.move(pos2.x, 0, pos2.y);
    //attach the actual vehicle objects to their respective nodes
    playerNode.attachChild(player);
    player2Node.attachChild(player2);
    
    // attach each playerNode to the root node
    rootNode.attachChild(playerNode);
    rootNode.attachChild(player2Node);
    
    
    
    initKeys(); // load my custom keybinding   
    
    // You must add a light to make the model visible
    DirectionalLight sun = new DirectionalLight();
    sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f));
    rootNode.addLight(sun);
    
    /*cam.setLocation(new Vector3f(1500,1500, 0));
    cam.lookAt(new Vector3f(0000,0,0), new Vector3f(0,1,0));
    
    */
    
    //set the came view distance to 15000 world units
    cam.setFrustumFar(15000);
    cam.onFrameChange();
    
    
    
    // Disable the default flyby cam
    flyCam.setEnabled(false);
    camNode = new CameraNode("Camera Node", cam);
    camNode.setControlDir(ControlDirection.SpatialToCamera);
    //create the camera Node
    //This mode means that camera copies the movements of the target:
    //Attach the camNode to the target:
    //playerNode.attachChild(camNode);
    //Move camNode, e.g. behind and above the target:
    //camNode.setLocalTranslation(new Vector3f(-200, 60, 0));
    //Rotate the camNode to look at the target:
    //camNode.lookAt(playerNode.getLocalTranslation(), Vector3f.UNIT_Y);
    
    
    chaseCam = new ChaseCamera(cam, player, inputManager);
    chaseCam.setSmoothMotion(true);
    chaseCam.setTrailingEnabled(true);
    chaseCam.setDefaultDistance(300);
    chaseCam.setMinDistance(300);
    chaseCam.setChasingSensitivity(5);
    //chaseCam.setDefaultVerticalRotation(FastMath.DEG_TO_RAD*15);
    //chaseCam.setTrailingRotationInertia((float).);
    //chaseCam.setStayBehindTarget(true);
    chaseCam.setRotationSpeed(2000);
    
    
    
  }
 
  /** Custom Keybinding: Map named actions to inputs. */
  private void initKeys() {
    // You can map one or several inputs to one named action
    inputManager.addMapping("Pause",  new KeyTrigger(KeyInput.KEY_P));
    inputManager.addMapping("Left",   new KeyTrigger(KeyInput.KEY_A), new JoyAxisTrigger(0, 0, true));
    inputManager.addMapping("Right",  new KeyTrigger(KeyInput.KEY_D), new JoyAxisTrigger(0, 0, false));
    inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE));
    inputManager.addMapping("Touch",  new TouchTrigger(0));
    // Add the names to the action listener.
    inputManager.addListener(actionListener, new String[]{"Pause"});
    inputManager.addListener(analogListener, new String[]{"Left", "Right", "Rotate"});
    inputManager.addListener(this, new String[]{"Touch"});
  }
 
  private ActionListener actionListener = new ActionListener() {
    public void onAction(String name, boolean keyPressed, float tpf) {
      if (name.equals("Pause") && !keyPressed) {
      }
    }
  };
 
  private AnalogListener analogListener = new AnalogListener() {
    public void onAnalog(String name, float value, float tpf) {
      if (isRunning) {
        if (name.equals("Rotate")) {
          player.rotate(0, value*speed, 0);
          
        }
        if (name.equals("Right")) {
          turnRight();
          
        }
        if (name.equals("Left")) {
            
          turnLeft();
          
        }
      } else {
        System.out.println("Press P to unpause.");
      }
    }
  };
  public void onTouch(String binding, TouchEvent evt, float tpf){
     float x;
     switch(evt.getType()){
         case MOVE:
           x = evt.getDeltaX();
             if(x>0){
                 Board.vehicleList.get(0).changeDirection(Board.vehicleList.get(0).getDirection()+3);
                 player.rotate(0, FastMath.DEG_TO_RAD*-3, 0);
             }
             else
             {
                Board.vehicleList.get(0).changeDirection(Board.vehicleList.get(0).getDirection()-3);
                player.rotate(0, FastMath.DEG_TO_RAD*3, 0); 
             }
             break; 
         /*case TAP:
             x = evt.getX();
             y = evt.getY();
             if(x < fscreenHeight){
                Board.vehicleList.get(0).changeDirection(Board.vehicleList.get(0).getDirection()-6);
                player.rotate(0, FastMath.DEG_TO_RAD*6, 0);
             }
             else{
                 Board.vehicleList.get(0).changeDirection(Board.vehicleList.get(0).getDirection()+6);
                 player.rotate(0, FastMath.DEG_TO_RAD*-6, 0);
             }
             break;*/
         case DOUBLETAP:
             Board.vehicleList.get(0).speedBoost();
             break;
          
     }
  }
  
  public void turnLeft()
  {
      Board.vehicleList.get(0).changeDirection(Board.vehicleList.get(0).getDirection()-3);
          player.rotate(0, FastMath.DEG_TO_RAD*3, 0);
          angle+=5;
          //camNode.setLocalTranslation(new Vector3f(-200*(int)Math.cos(Math.abs(angle)), 60, (int)Math.sin(Math.abs(angle))*(200)));
  }
  
  public void turnRight()
  {
      Board.vehicleList.get(0).changeDirection(Board.vehicleList.get(0).getDirection()+3);
          player.rotate(0, FastMath.DEG_TO_RAD*-3, 0);
          
          angle-=5;
          //camNode.setLocalTranslation(new Vector3f(-200*(int)Math.cos(Math.abs(angle)), 60, (int)Math.sin(Math.abs(angle))*(-200)));
  }
}